
package org.dyndns.cooland.updater;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.net.Proxy;
import java.util.Iterator;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
import javax.swing.JTree;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.GroupLayout.Alignment;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.border.EmptyBorder;
import javax.swing.border.EtchedBorder;
import javax.swing.event.TreeModelListener;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.TreeCellRenderer;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreePath;

import org.dyndns.cooland.updater.db.OUTStore;
import org.dyndns.cooland.updater.db.dao.AddonDAO;
import org.dyndns.cooland.updater.db.dao.CategoryDAO;
import org.dyndns.cooland.updater.db.dao.SitesDAO;
import org.dyndns.cooland.updater.db.model.Addon;
import org.dyndns.cooland.updater.db.model.Bean;
import org.dyndns.cooland.updater.db.model.Category;
import org.dyndns.cooland.updater.db.model.Sites;
import org.dyndns.cooland.updater.dialogs.ManageSitesDlg;
import org.dyndns.cooland.updater.downloader.OUTDownloader;

public class UpdaterGUI extends JDialog {
	
	private static final long	serialVersionUID	= -1935751021230100787L;
	private final JPanel		contentPanel		= new JPanel();
	private JTextField			txtSearchText;
	private JLabel				lblWorkWithLabel;
	private JComboBox			currentSite;
	private JButton				btnManageButton;
	private JLabel				lblVariableTextLabel;
	private JTree				tree;
	private JLabel				lblDetLabel;
	private JProgressBar		progressBar;
	private JCheckBox			chckbxSourceAndDocs;
	private JCheckBox			chckbxHideInstalledItems;
	private JCheckBox			chckbxShowOnlyLatest;
	private JCheckBox			chckbxGroupByCategory;
	private OUTDownloader		downloader;
	private File				catalog;
	private OUTStore			store				= null;
	JLabel						lblDetailsLabel		= new JLabel("");
	DefaultComboBoxModel		sitesModel			= new DefaultComboBoxModel();
	SitesDAO					sites_dao			= new SitesDAO();
	public static String		MAIN_DIRECTORY		= "updater";
	private Loader				loader				= null;
	
	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {

		try{
			UIManager
					.setLookAndFeel("com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
			UpdaterGUI dialog = new UpdaterGUI();
			dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
			dialog.setVisible(true);
		}
		catch (Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * Create the dialog.
	 */
	public UpdaterGUI () {

		setModal(true);
		setResizable(false);
		setTitle("Orbiter Updater");
		setBounds(100, 100, 893, 677);
		getContentPane().setLayout(new BorderLayout());
		contentPanel.setBorder(new EmptyBorder(5, 5, 5, 5));
		getContentPane().add(contentPanel, BorderLayout.CENTER);
		{
			lblWorkWithLabel = new JLabel("Work with:");
		}
		{
			currentSite = new JComboBox(sitesModel);
			currentSite.setEditable(true);
			currentSite.getEditor().getEditorComponent().addKeyListener(
					new KeyAdapter() {
						
						@Override
						public void keyPressed(KeyEvent e) {

							if (e.getKeyCode() == KeyEvent.VK_ENTER){
								// TODO если включен editable, то проверить
								// getItem это объект SitesBean(выбор из
								// комбобокса) или просто String(ввод текста)
								Sites bean = (Sites) currentSite.getEditor()
										.getItem();
								downloadCatalog(bean);
							}
						}
					});
		}
		{
			btnManageButton = new JButton("Manage ...");
			btnManageButton.addActionListener(new ActionListener() {
				
				public void actionPerformed(ActionEvent e) {

					ManageSitesDlg dlg = new ManageSitesDlg(store);
					dlg.setVisible(true);
					updateSitesModel();
				}
			});
		}
		{
			// Для каких-нибудь сообщений
			lblVariableTextLabel = new JLabel("New label");
			lblVariableTextLabel.setVisible(false);
		}
		{ // TODO сделать поиск по tree и показывать только что искали
			txtSearchText = new JTextField();
			txtSearchText.setEnabled(false);
			txtSearchText.setText("search text ...");
			txtSearchText.setColumns(10);
		}
		{
			lblDetLabel = new JLabel("Details:");
		}
		{
			progressBar = new JProgressBar();
			progressBar.setVisible(false);
			progressBar.setFocusTraversalKeysEnabled(false);
			progressBar.setFocusable(false);
			progressBar.setStringPainted(true);
		}
		{
			chckbxSourceAndDocs = new JCheckBox("Download source&docs");
			chckbxSourceAndDocs
					.setToolTipText("Download source and docs packets if available");
			chckbxSourceAndDocs.setHorizontalAlignment(SwingConstants.LEFT);
		}
		{
			chckbxHideInstalledItems = new JCheckBox("Hide installed items");
			chckbxHideInstalledItems
					.setToolTipText("Show only not installed packages  ");
			chckbxHideInstalledItems
					.setHorizontalAlignment(SwingConstants.LEFT);
		}
		{
			chckbxShowOnlyLatest = new JCheckBox(
					"Show only the latest versions");
			chckbxShowOnlyLatest
					.setToolTipText("Show only the latest available package version ");
			chckbxShowOnlyLatest.setHorizontalAlignment(SwingConstants.LEFT);
		}
		{
			chckbxGroupByCategory = new JCheckBox("Group by category");
			chckbxGroupByCategory.setHorizontalAlignment(SwingConstants.LEFT);
		}
		
		JPanel logoPane = new JPanel();
		logoPane.setBorder(new EtchedBorder(EtchedBorder.LOWERED, null, null));
		logoPane.setBackground(Color.CYAN);
		
		JScrollPane scrollPane = new JScrollPane();
		scrollPane
				.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
		
		JButton btnGo = new JButton("Go");
		btnGo.addActionListener(new ActionListener() {
			
			public void actionPerformed(ActionEvent e) {

				// TODO если включен editable, то проверить getItem это объект
				// SitesBean(выбор из комбобокса) или просто String(ввод текста)
				Sites bean = (Sites) currentSite.getEditor().getItem();
				downloadCatalog(bean);
			}
		});
		
		GroupLayout gl_contentPanel = new GroupLayout(contentPanel);
		gl_contentPanel
				.setHorizontalGroup(gl_contentPanel
						.createParallelGroup(Alignment.TRAILING)
						.addGroup(
								gl_contentPanel
										.createSequentialGroup()
										.addGroup(
												gl_contentPanel
														.createParallelGroup(
																Alignment.LEADING)
														.addGroup(
																gl_contentPanel
																		.createSequentialGroup()
																		.addGroup(
																				gl_contentPanel
																						.createParallelGroup(
																								Alignment.TRAILING,
																								false)
																						.addComponent(
																								chckbxSourceAndDocs,
																								GroupLayout.DEFAULT_SIZE,
																								GroupLayout.DEFAULT_SIZE,
																								Short.MAX_VALUE)
																						.addComponent(
																								chckbxShowOnlyLatest,
																								GroupLayout.PREFERRED_SIZE,
																								203,
																								GroupLayout.PREFERRED_SIZE))
																		.addPreferredGap(
																				ComponentPlacement.UNRELATED)
																		.addGroup(
																				gl_contentPanel
																						.createParallelGroup(
																								Alignment.LEADING)
																						.addComponent(
																								chckbxGroupByCategory)
																						.addComponent(
																								chckbxHideInstalledItems)))
														.addComponent(
																logoPane,
																GroupLayout.PREFERRED_SIZE,
																880,
																GroupLayout.PREFERRED_SIZE)
														.addGroup(
																gl_contentPanel
																		.createParallelGroup(
																				Alignment.TRAILING)
																		.addGroup(
																				gl_contentPanel
																						.createSequentialGroup()
																						.addComponent(
																								lblVariableTextLabel)
																						.addGap(
																								31))
																		.addGroup(
																				gl_contentPanel
																						.createSequentialGroup()
																						.addComponent(
																								lblWorkWithLabel,
																								GroupLayout.PREFERRED_SIZE,
																								69,
																								GroupLayout.PREFERRED_SIZE)
																						.addPreferredGap(
																								ComponentPlacement.RELATED)
																						.addComponent(
																								currentSite,
																								GroupLayout.PREFERRED_SIZE,
																								648,
																								GroupLayout.PREFERRED_SIZE)
																						.addPreferredGap(
																								ComponentPlacement.RELATED)
																						.addComponent(
																								btnGo)
																						.addGap(
																								14)
																						.addComponent(
																								btnManageButton)
																						.addPreferredGap(
																								ComponentPlacement.RELATED)))
														.addGroup(
																gl_contentPanel
																		.createParallelGroup(
																				Alignment.LEADING)
																		.addGroup(
																				gl_contentPanel
																						.createSequentialGroup()
																						.addComponent(
																								lblDetLabel)
																						.addPreferredGap(
																								ComponentPlacement.RELATED)
																						.addComponent(
																								lblDetailsLabel,
																								GroupLayout.DEFAULT_SIZE,
																								838,
																								Short.MAX_VALUE))
																		.addComponent(
																				progressBar,
																				GroupLayout.PREFERRED_SIZE,
																				871,
																				GroupLayout.PREFERRED_SIZE)))
										.addGap(24))
						.addGroup(
								gl_contentPanel
										.createSequentialGroup()
										.addGroup(
												gl_contentPanel
														.createParallelGroup(
																Alignment.LEADING)
														.addGroup(
																gl_contentPanel
																		.createSequentialGroup()
																		.addGap(
																				14)
																		.addComponent(
																				txtSearchText,
																				GroupLayout.DEFAULT_SIZE,
																				858,
																				Short.MAX_VALUE))
														.addGroup(
																gl_contentPanel
																		.createSequentialGroup()
																		.addContainerGap()
																		.addComponent(
																				scrollPane,
																				GroupLayout.DEFAULT_SIZE,
																				862,
																				Short.MAX_VALUE)))
										.addGap(32)));
		gl_contentPanel.setVerticalGroup(gl_contentPanel.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_contentPanel.createSequentialGroup().addComponent(logoPane,
						GroupLayout.PREFERRED_SIZE, 45,
						GroupLayout.PREFERRED_SIZE).addGap(4).addGroup(
						gl_contentPanel.createParallelGroup(Alignment.BASELINE)
								.addComponent(lblWorkWithLabel).addComponent(
										currentSite,
										GroupLayout.PREFERRED_SIZE, 20,
										GroupLayout.PREFERRED_SIZE)
								.addComponent(btnGo).addComponent(
										btnManageButton)).addPreferredGap(
						ComponentPlacement.RELATED).addComponent(
						lblVariableTextLabel).addGap(18).addComponent(
						txtSearchText, GroupLayout.PREFERRED_SIZE,
						GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(scrollPane, GroupLayout.DEFAULT_SIZE,
								275, Short.MAX_VALUE).addPreferredGap(
								ComponentPlacement.RELATED).addGroup(
								gl_contentPanel.createParallelGroup(
										Alignment.BASELINE).addComponent(
										lblDetLabel).addComponent(
										lblDetailsLabel,
										GroupLayout.PREFERRED_SIZE, 14,
										GroupLayout.PREFERRED_SIZE))
						.addPreferredGap(ComponentPlacement.RELATED)
						.addComponent(progressBar, GroupLayout.PREFERRED_SIZE,
								GroupLayout.DEFAULT_SIZE,
								GroupLayout.PREFERRED_SIZE).addGap(18)
						.addGroup(
								gl_contentPanel.createParallelGroup(
										Alignment.LEADING).addComponent(
										chckbxHideInstalledItems).addComponent(
										chckbxSourceAndDocs)).addGap(5)
						.addGroup(
								gl_contentPanel.createParallelGroup(
										Alignment.BASELINE).addComponent(
										chckbxShowOnlyLatest).addComponent(
										chckbxGroupByCategory)).addGap(61)));
		{
			tree = new JTree();
			TreeCellRenderer cellrenderer = new AddonsTreeCellRenderer();
			tree.setCellRenderer(cellrenderer);
			TreeModel treeModel = new AddonsTreeModel();
			tree.setModel(treeModel);
			tree.setAutoscrolls(true);
			scrollPane.setViewportView(tree);
			tree.setRootVisible(false);
			tree.setBorder(null);
		}
		// TODO заменить картинку
		JLabel lblLogo = new JLabel("");
		lblLogo.setIcon(new ImageIcon(UpdaterGUI.class
				.getResource("/javax/swing/plaf/basic/icons/JavaCup16.png")));
		
		JLabel lblOrbiterUpdateTool = new JLabel("Orbiter Update Tool v.1.0");
		lblOrbiterUpdateTool.setFont(new Font("Cambria Math", Font.PLAIN, 18));
		
		GroupLayout gl_logoPane = new GroupLayout(logoPane);
		gl_logoPane.setHorizontalGroup(gl_logoPane.createParallelGroup(
				Alignment.LEADING).addGroup(
				gl_logoPane.createSequentialGroup().addContainerGap()
						.addComponent(lblLogo, GroupLayout.PREFERRED_SIZE, 47,
								GroupLayout.PREFERRED_SIZE).addGap(18)
						.addComponent(lblOrbiterUpdateTool).addContainerGap(
								747, Short.MAX_VALUE)));
		gl_logoPane.setVerticalGroup(gl_logoPane.createParallelGroup(
				Alignment.LEADING).addGroup(
				Alignment.TRAILING,
				gl_logoPane.createSequentialGroup().addGroup(
						gl_logoPane.createParallelGroup(Alignment.TRAILING)
								.addGroup(
										gl_logoPane.createSequentialGroup()
												.addContainerGap()
												.addComponent(
														lblOrbiterUpdateTool))
								.addComponent(lblLogo,
										GroupLayout.DEFAULT_SIZE, 41,
										Short.MAX_VALUE)).addContainerGap()));
		logoPane.setLayout(gl_logoPane);
		contentPanel.setLayout(gl_contentPanel);
		{
			JPanel buttonPane = new JPanel();
			buttonPane.setLayout(new FlowLayout(FlowLayout.RIGHT));
			getContentPane().add(buttonPane, BorderLayout.SOUTH);
			{
				JButton okButton = new JButton("Update");
				// okButton.setActionCommand("OK");
				buttonPane.add(okButton);
				getRootPane().setDefaultButton(okButton);
			}
			{
				JButton cancelButton = new JButton("Cancel");
				cancelButton.addActionListener(new ActionListener() {
					
					public void actionPerformed(ActionEvent e) {

						dispose();
					}
				});
				cancelButton.setActionCommand("Cancel");
				buttonPane.add(cancelButton);
			}
		}
		
		JMenuBar menuBar = new JMenuBar();
		setJMenuBar(menuBar);
		
		JMenu mnFile = new JMenu("File");
		menuBar.add(mnFile);
		
		JMenuItem mntmOpen = new JMenuItem("Open");
		mnFile.add(mntmOpen);
		mnFile.addSeparator();
		
		JMenuItem mntmExit = new JMenuItem("Exit");
		mnFile.add(mntmExit);
		
		JMenu mnEdit = new JMenu("Edit");
		menuBar.add(mnEdit);
		
		JMenuItem mntmPreferences = new JMenuItem("Preferences");
		mnEdit.add(mntmPreferences);
		
		JMenu mnHelp = new JMenu("Help");
		menuBar.add(mnHelp);
		
		JMenuItem mntmAboutOrbiterUpdate = new JMenuItem(
				"About Orbiter Update Tool");
		mnHelp.add(mntmAboutOrbiterUpdate);
		
		// /////////////////////////////////////////////////////////////////////////////
		
		// Check for working directory exists
		File working_dir = new File(MAIN_DIRECTORY);
		if (!(working_dir.isDirectory() && working_dir.exists())){
			// TODO позволить выбрать рабочий каталог
			int selection = JOptionPane.showConfirmDialog(null, "Directory "
					+ working_dir.getAbsolutePath()
					+ " does not exists.\n Want to create?",
					"Create directory", JOptionPane.OK_CANCEL_OPTION,
					JOptionPane.INFORMATION_MESSAGE);
			switch (selection) {
				case JOptionPane.OK_OPTION:
					// create directory
					if (!working_dir.mkdir()){
						// failed to create
						JOptionPane.showMessageDialog(null,
								"Error creating directory "
										+ working_dir.getAbsolutePath()
										+ "\n Exit.", "Error",
								JOptionPane.ERROR_MESSAGE);
						this.dispose();
						System.exit(1);
					}
					break;
				case JOptionPane.CANCEL_OPTION:
					JOptionPane.showMessageDialog(null,
							"Cant continue without working directory \n Exit.",
							"Error", JOptionPane.ERROR_MESSAGE);
					this.dispose();
					System.exit(1);
					break;
				default:
					break;
			}
		}
		// /////////////////////////////////////////////////////////////////////////////
		
		try{
			store = new OUTStore();
			if (store.notConfigured()){
				int selection = JOptionPane.showConfirmDialog(null,
						"Database does not exists.\n Want to create?",
						"Create database", JOptionPane.OK_CANCEL_OPTION,
						JOptionPane.INFORMATION_MESSAGE);
				switch (selection) {
					case JOptionPane.OK_OPTION:
						// create database
						store.createDefaultDatabase();
						lblDetailsLabel.setText("default database created");
						
						break;
					case JOptionPane.CANCEL_OPTION:
						JOptionPane.showMessageDialog(null,
								"Cant continue without a database \n Exit.",
								"Error", JOptionPane.ERROR_MESSAGE);
						this.dispose();
						System.exit(1);
						break;
					default:
						break;
				}
			}
		}
		catch (Exception e){
			e.printStackTrace();
		}
		// TODO сделать OUTdownloader многопоточным и чтобы можно было запускать
		// отдельно (обновление самого клиента и обновление в фоне)
		downloader = new OUTDownloader();
		
		// Fill currentSite combobox
		updateSitesModel();
		
	}
	
	/*
	 * Update sites combo box from DB
	 */
	private void updateSitesModel() {

		sitesModel.removeAllElements();
		List<Sites> list = sites_dao.selectAll();
		Iterator<Sites> it = list.listIterator();
		while (it.hasNext()){
			Sites site = it.next();
			if (site.getEnabled() == 1){
				sitesModel.addElement(site);
			}
		}
	}
	
	/*
	 * Download catalog.zip from url
	 */
	private void downloadCatalog(Sites bean) {

		downloadFile(bean.getUrl(), "catalog.zip", bean);
	}
	
	private void downloadFile(String site_url, String filename, Bean bean) {

		InetLoaderCallback ui = (InetLoaderCallback) java.lang.reflect.Proxy
				.newProxyInstance(getClass().getClassLoader(),
						new Class[] { InetLoaderCallback.class },
						new EDTInvocationHandler(new InetLoaderCallbackImpl()));
		
		String url = site_url;
		if (!url.endsWith("/")){
			url += "/";
		}
		
		String path = MAIN_DIRECTORY + File.separator + "download"
				+ File.separator
				+ org.apache.commons.codec.digest.DigestUtils.md5Hex(url);
		
		File f = new File(path);
		if (!f.isDirectory()){
			f.mkdirs();
		}
		
		// TODO proxy, timeouts
		loader = new org.dyndns.cooland.updater.Loader(ui, url + filename, path
				+ File.separator + filename, Proxy.NO_PROXY, 10000, 10000, bean);
		loader.execute();
		
	}
	
	/*
	 * unzip file into folder
	 */
	private void unZip(String zipFile, String outputFolder) {

		byte[] buffer = new byte[1024];
		try{
			// create output folder if not exists
			File folder = new File(outputFolder);
			if (!folder.exists()){
				folder.mkdir();
			}
			
			ZipInputStream zis = new ZipInputStream(
					new FileInputStream(zipFile));
			ZipEntry ze = zis.getNextEntry();
			
			while (ze != null){
				String fileName = ze.getName();
				File newFile = new File(outputFolder + File.separator
						+ fileName);
				
				// create all non exists folders
				new File(newFile.getParent()).mkdirs();
				
				FileOutputStream fos = new FileOutputStream(newFile);
				
				int len;
				while ((len = zis.read(buffer)) > 0){
					fos.write(buffer, 0, len);
				}
				fos.close();
				ze = zis.getNextEntry();
			}
			zis.closeEntry();
			zis.close();
		}
		catch (IOException ex){
			ex.printStackTrace();
		}
	}
	
	/*
	 * called when download is finished
	 */
	private void stopDownload(String path, String url, Bean bean) {

		catalog = new File(path);
		if (catalog == null || !catalog.canRead()){
			JOptionPane.showMessageDialog(null,
					"Error downloading catalog from site " + url, "Error",
					JOptionPane.ERROR_MESSAGE);
			lblDetailsLabel.setText("cant read file " + path);
			return;
		}
		
		progressBar.setVisible(false);
		
		// start parse catalog file
		if (bean instanceof Sites){
			// unpack catalog file
			lblDetailsLabel.setText("start unzip catalog");
			unZip(path, new File(path).getParent());
			lblDetailsLabel.setText("unzip catalog fifnished");
			
			lblDetailsLabel.setText("start parse catalog");
			CatalogParser parser = new CatalogParser();
			
			try{
				parser.parse(new File(new File(path).getParent()
						+ File.separator + "catalog.xml"), bean.getId());
			}
			catch (Exception e){
				lblDetailsLabel.setText("error while parsing catalog");
				e.printStackTrace();
				return;
			}
			
			lblDetailsLabel.setText("parsing catalog finished");
		}
		
	}
	
	private class InetLoaderCallbackImpl implements InetLoaderCallback {
		
		public void setProgress(final int progressPercent) {

			progressBar.setValue(progressPercent);
		}
		
		public void startLoading() {

			currentSite.setEnabled(false);
			lblDetailsLabel.setText("start downloading");
			progressBar.setVisible(true);
			progressBar.setValue(0);
		}
		
		public void stopLoading(String path, String url, Bean bean) {

			lblDetailsLabel.setText("downloading finished");
			currentSite.setEnabled(true);
			progressBar.setValue(100);
			stopDownload(path, url, bean);
		}
		
		public void showError(final String message) {

			JOptionPane.showMessageDialog(null, message, "Error",
					JOptionPane.ERROR_MESSAGE);
		}
		
		public void setText(String text) {

			lblDetailsLabel.setText(text);
		}
	}
	
}

// TODO TreeModel from database
class AddonsTreeModel implements TreeModel {
	
	CategoryDAO	cdao		= new CategoryDAO();
	AddonDAO	dao			= new AddonDAO();
	
	Category	rootNode	= new Category();
	
	public AddonsTreeModel () {

		rootNode.setId(-1);
		rootNode.setName("category");
		rootNode.setParent_id(-1);
	}
	
	public Object getRoot() {

		return rootNode;
	}
	
	public void addTreeModelListener(TreeModelListener l) {

	}
	
	public int getChildCount(Object parent) {

		int count = -1;
		if (parent instanceof Category){
			if (((Category) parent).getId() == -1){
				count = cdao.selectByParentId(0).size();
			}
			else{
				count = (dao.selectByCategoryId(((Category) parent).getId()))
						.size();
			}
		}
		return count;
	}
	
	public Object getChild(Object parent, int index) {

		if (parent instanceof Category){
			if (((Category) parent).getId() == -1){
				List<Category> list = cdao.selectByParentId(0);
				return list.get(index);
			}
			else{
				int id = ((Category) parent).getId();
				List<Category> list = cdao.selectByParentId(id);
				if (list.isEmpty()){
					List<Addon> alist = dao
							.selectByCategoryId(((Category) parent).getId());
					if (!alist.isEmpty()){
						return alist.get(index);
					}
				}
				else{
					return list.get(index);
				}
			}
		}
		return null;
	}
	
	public int getIndexOfChild(Object parent, Object child) {

		if (parent instanceof Category){
			if (((Category) parent).getId() == -1){
				List<Category> list = cdao.selectByParentId(0);
				for (int i = 0; i < list.size(); i++){
					if (list.get(i) == (Category) child){
						return i;
					}
				}
			}
			else{
				List<Category> list = cdao.selectByParentId(((Category) parent)
						.getId());
				if (!list.isEmpty()){
					for (int i = 0; i < list.size(); i++){
						if (list.get(i) == (Category) child){
							return i;
						}
					}
				}
				else{
					List<Addon> alist = dao
							.selectByCategoryId(((Category) parent).getId());
					for (int i = 0; i < alist.size(); i++){
						if (alist.get(i) == (Addon) child){
							return i;
						}
					}
				}
			}
		}
		
		return -1;
	}
	
	public boolean isLeaf(Object node) {

		boolean result = true;
		
		if (node instanceof Category){
			int count = -1;
			if (((Category) node).getId() == -1){
				count = (cdao.selectByParentId(0)).size();
			}
			else{
				count = (dao.selectByCategoryId(((Category) node).getId())
						.size());
			}
			
			if (count > 0) result = false;
		}
		return result;
	}
	
	public void removeTreeModelListener(TreeModelListener l) {

	}
	
	public void valueForPathChanged(TreePath path, Object newValue) {

	}
	
}

class AddonsTreeCellRenderer implements TreeCellRenderer {
	
	protected DefaultTreeCellRenderer	defaultRenderer	= new DefaultTreeCellRenderer();
	
	public Component getTreeCellRendererComponent(JTree tree, Object value,
			boolean selected, boolean expanded, boolean leaf, int row,
			boolean hasFocus) {

		Component renderer = defaultRenderer.getTreeCellRendererComponent(tree,
				value, selected, expanded, leaf, row, hasFocus);
		
		if (value != null){
			if (value instanceof Category){
				((JLabel) renderer).setText(((Category) value).getName());
			}
			else if (value instanceof Addon){
				((JLabel) renderer).setText(((Addon) value).getName());
			}
			
		}
		return renderer;
	}
}
